




#include "../inc/dllemvb.h"
#include <stdarg.h>



static struct avl_table *emvtree = NULL;
static unsigned int gcurtagtype = TAGTYPE_EMV;


extern EMVBallocator gEmvballocator;



void emvb_printf(char *fmt,...)
{
	if(gEmvballocator.emvb_printf != NULL)
	{
		va_list ap;
		//s8 *pt;
		char string[256];
	    
		va_start(ap,fmt);
		vsprintf((char *)string,(const char *)fmt,ap);
		gEmvballocator.emvb_printf("%s", string);  //sxl?
		va_end(ap);
	}
}






// 20160808 
int	compare_EMVtagitems(const void *pa, const void *pb, void *param)
{
  const EMVTAGCVLITEM *itema = (EMVTAGCVLITEM *)pa;
  const EMVTAGCVLITEM *itemb = (EMVTAGCVLITEM *)pb;
  int i;
  unsigned int a = 0;
  unsigned int b = 0;

  for(i = 0;i < 4;i++)
  {
  	a = (a<<8) + itema->Tag[i];
	b = (b<<8) + itemb->Tag[i];
  }
  
  if (a < b)
    return -1;
  else if (a > b)
    return +1;
  else
    return 0;
  
  
}




// 20140320
void dllemv_avl_deletetagdata (void *avl_item, void *avl_param)
{
	
	EMVTAGCVLITEM *item;
    
	item = (EMVTAGCVLITEM *)avl_item;
    
    if(emvtree == NULL)
    {
    	return;

    }
    
	if(item != NULL)
	{
		if(item->data != NULL)
		{
			emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, item->data);
			item->data = NULL;
		}
		emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, item);
	}
    
	avl_item = NULL;
}


//20140320
int dllemvb_avl_create(void)
{
	if(emvtree != NULL)
	{
		dllemvb_avl_destory();
	}

	emvtree = avl_create (compare_EMVtagitems, NULL, NULL);
	if (emvtree == NULL)
	{
		emvb_printf("\r\n Out of memory creating tree.");
		return 1;
	}

	return 0;
}



//20140320
void dllemvb_avl_destory(void)
{
	if(emvtree != NULL)
	{
		avl_destroy(emvtree, dllemv_avl_deletetagdata);
		emvtree = NULL;
	}
    
	
}


//20140320
unsigned char dllemvb_avl_checktreestatus(void)
{
	if(emvtree != NULL)
	{
		return 1;
	}
	
	return 0;
}




//20140320
void dllemvb_avl_delete(unsigned char *tag)
{
	EMVTAGCVLITEM *item;
	EMVTAGCVLITEM *itemreturn;

    if(emvtree == NULL)
    {
    	return;
    }

	item = dllemvb_avl_gettagitempointer(tag);
	if(item == NULL)
	{
		return;
	}
	
	itemreturn = (EMVTAGCVLITEM *)avl_delete(emvtree,(void *)item);

	if(itemreturn != NULL)
	{
		if(itemreturn->data != NULL)
		{
			emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, itemreturn->data);
			itemreturn->data = NULL;
		}
		emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, itemreturn);
	}
}

//20140320
int dllemvb_avl_find(unsigned char *tag,unsigned char taglen,void *param)
{
	EMVTAGCVLITEM *item;
    
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
    
    
	if(emvtree == NULL)
	{
		return TAGNOTEXIST;
	}
    
	
	gEmvballocator.EMVBallocator_memset((unsigned char *)&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (taglen>4) ? 4:(taglen);
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
    
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
	if(item == NULL)
	{
		return TAGNOTEXIST;
	}
    
	return (item->len)?(TAGEXIST):(TAGEMPTY);
}



//20140320
int dllemvb_avl_read(unsigned char *tag,unsigned char taglen,unsigned char *tagdata,unsigned short *tagdatalen,void *param)
{
    unsigned int len;
	//unsigned int i;

	
	EMVTAGCVLITEM *item;
    
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
    
    
	if(emvtree == NULL)
	{
		return TAGNOTEXIST;
	}
    
	
	gEmvballocator.EMVBallocator_memset((unsigned char *)&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (taglen>4) ? 4:(taglen);
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
    
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
	if(item == NULL)
	{
		return TAGNOTEXIST;
	}

    len = *tagdatalen;
    *tagdatalen = (item->len >len)?(len):(item->len);
	if(*tagdatalen)
	{
	    if(item->data != NULL)
	    {
			gEmvballocator.EMVBallocator_memcpy(tagdata,item->data,*tagdatalen);
	    }
		
	}
    
	return (item->len)?(TAGEXIST):(TAGEMPTY);
}




//20140320
int dllemvb_avl_insert(EMVTAGCVLITEM *storeditem,unsigned char *tag,unsigned char taglen,unsigned char *tagdata,unsigned short tagdatalen,void *param)
{
    EMVTAGCVLITEM *item;
	//EMVTAGCVLITEM *item1;
    EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
	unsigned char itemfind = 0;
	int rslt;

    if(tag == NULL)
    {
    	return 1;
    }
    if(gEmvballocator.EMVBallocator_memcmp(tag,"\x00\x00\x00\x00",4) == 0)
	{
		return 1;
    }
    
	#ifdef EMVB_DEBUG
	if(gEmvballocator.EMVBallocator_memcmp(tag,"\x00\x00\x00\x00",4) == 0)
	{
	    while(1)
	    {
	    	 emvb_printf("\r\n tag err");
	    }
		return 0;
	}
	#endif
    
	
	if(emvtree == NULL)
	{
		return 1;
	}
	
	gEmvballocator.EMVBallocator_memset((unsigned char *)&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (taglen>4) ? 4:(taglen);
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
//	API_TraceHex(DBG_APP_INFO,"\r\n avl_find",item,tagdatalen);		
	
	if(item != NULL)
	{
		itemfind = 1;
		if(item->len)
		{
		    if(item->data != NULL)
		    {
				emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, item->data);
				item->data = NULL;
		    }
			item->len = 0;
		}
        
		
	}
    else
    {
    	item = (EMVTAGCVLITEM *)emvtree->avl_alloc->libavl_malloc(emvtree->avl_alloc,sizeof(EMVTAGCVLITEM));
		gEmvballocator.EMVBallocator_memset((unsigned char *)item,0,sizeof(EMVTAGCVLITEM));
        gEmvballocator.EMVBallocator_memcpy(item->Tag,tag,savetaglen);
    }

    if(storeditem != NULL)
    {
    	gEmvballocator.EMVBallocator_memcpy((unsigned char *)item,(unsigned char *)storeditem,sizeof(EMVTAGCVLITEM));
    }
    else
    {
    	gEmvballocator.EMVBallocator_memset((unsigned char *)&tempitem,0,sizeof(EMVTAGCVLITEM));
		rslt = EMVB_TagBaseLib_read(tag,taglen,gcurtagtype,&tempitem); //sxl????????????????????????????
		if(rslt == 1)
		{
		    //unfind
            //API_Trace(DBG_APP_INFO,"\r\n Tag unfind:%02x %02x %02x, Tag Len: %d",tag[0],tag[1],tag[2],savetaglen);

		    if(itemfind == 0)
		    {
		    	
		        if(gcurtagtype == TAGTYPE_PAYWAVE)
		        {
		        	rslt = EMVB_TagBaseLib_read(tag,taglen,TAGTYPE_EMV,&tempitem);
		        }

				
				if(itemfind == 0&&rslt == 1)
				{
			    	gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
					tempitem.updatecondition = TAGUPDATECONDITION_K;
					tempitem.datafomat = TAGFORMAT_B;
	                tempitem.SupAppType = TAGTYPE_NULL;

					gEmvballocator.EMVBallocator_memcpy((unsigned char *)item,(unsigned char *)&tempitem,sizeof(EMVTAGCVLITEM));
				}
		    }

		}
        else
        {
        	gEmvballocator.EMVBallocator_memcpy((unsigned char *)item,&tempitem,sizeof(EMVTAGCVLITEM));
        }
		
    }
    
	
	item->len = tagdatalen;
    if(item->len)
    {
    	item->data = (unsigned char *)emvtree->avl_alloc->libavl_malloc(emvtree->avl_alloc,item->len);
		//assert (item->data != NULL);
    }
	
	if(tagdata != NULL && item->len)
	{
    	gEmvballocator.EMVBallocator_memcpy(item->data,tagdata,item->len);
	}

    
	if(gEmvballocator.EMVBallocator_memcmp(item->Tag,"\x00\x00\x00\x00",4) == 0)  
	{
		if(itemfind == 0)
		{
		    if(item != NULL)
		    {
				if(item->data != NULL)
			    {
					emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, item->data);
					item->data = NULL;
			    }
				emvtree->avl_alloc->libavl_free(emvtree->avl_alloc, item);
				item = NULL;
		    }
			
		}
		return 1;
	}
	
	
    
	if(itemfind == 0)
	{
		avl_insert(emvtree,item);   //item1 = 
		//assert (item1 == NULL);
	}
    
    
	
	return 0;
    
    
	
}


//20140320
int dllemvb_avl_createsettagvalue(unsigned char *tag,unsigned char *tagdata,unsigned short tagdatalen)
{
	return dllemvb_avl_insert(NULL,tag,gEmvballocator.EMVBallocator_strlen((char *)tag),tagdata,tagdatalen,NULL);
}


//20140320
int dllemvb_avl_set(unsigned char *tag,unsigned char tagdata)
{
	return dllemvb_avl_insert(NULL,tag,gEmvballocator.EMVBallocator_strlen((char *)tag),&tagdata,1,NULL);
}


//20140320
unsigned char dllemvb_avl_gettagvalue(unsigned char *tag)
{
    int rst;
	unsigned short len;
	unsigned char data;
    
	
	len = 1;
	rst = dllemvb_avl_read(tag,gEmvballocator.EMVBallocator_strlen((char *)tag),&data,&len,NULL);
    if(rst == TAGEXIST)
    {
    	if(len)
    	{
    		return data;
    	}
    }
    
    
	return 0;
}


//20140320
unsigned char dllemvb_avl_gettagvalue_spec(unsigned char *tag,unsigned char *tagdata,unsigned short strpos,unsigned short len)
{
    EMVTAGCVLITEM *tagitem;
	//int i;
	
    tagitem = dllemvb_avl_gettagitempointer(tag);
    if(tagitem != NULL)
    {
		if(tagitem->data != NULL)
		{
			if(strpos <= tagitem->len &&(strpos+len) <= tagitem->len)
			{
			    gEmvballocator.EMVBallocator_memcpy(tagdata,&tagitem->data[strpos],len);
				return 0;
			}
		}
	}

	return 1;
}



//20140320
unsigned char dllemvb_avl_gettagvalue_all(unsigned char *tag,unsigned char *tagdata,unsigned short *len)
{
    EMVTAGCVLITEM *tagitem;
	
    tagitem = dllemvb_avl_gettagitempointer(tag);
    if(tagitem != NULL)
    {
    	//API_TraceHex(DBG_APP_INFO,"\r\n tagitem->data",tagitem->data,tagitem->len);
		
		if(tagitem->data != NULL)
		{
			
		    gEmvballocator.EMVBallocator_memcpy(tagdata,tagitem->data,tagitem->len);
			*len = tagitem->len;
			return 0;
		}
	}

    *len = 0;
	return 1;
}



//20140320
unsigned char *dllemvb_avl_gettagvaluepointer(unsigned char *tag)
{
	//unsigned int len;
    
	
	EMVTAGCVLITEM *item;
    
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
    
    
	if(emvtree == NULL)
	{
		return NULL;
	}
    
	
	gEmvballocator.EMVBallocator_memset(&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (gEmvballocator.EMVBallocator_strlen((char *)tag)>4) ? 4:(gEmvballocator.EMVBallocator_strlen((char *)tag));
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
    
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
	if(item == NULL || item->len == 0)
	{
		return NULL;
	}
    
	return item->data;
    
	
}


//20140320
EMVTAGCVLITEM *dllemvb_avl_gettagitempointer(unsigned char *tag)
{
	//unsigned int len;
    
	
	EMVTAGCVLITEM *item;
    
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
    
    
	if(emvtree == NULL)
	{
		return NULL;
	}
    
	
	gEmvballocator.EMVBallocator_memset(&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (gEmvballocator.EMVBallocator_strlen((char *)tag)>4) ? 4:(gEmvballocator.EMVBallocator_strlen((char *)tag));
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
    
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
    
	
	return item;
    
	
}


//20140320
void dllemvb_avl_setvalue_and(unsigned char *tag,unsigned short  position,unsigned char anddata)
{
	EMVTAGCVLITEM *item;
    
	item = dllemvb_avl_gettagitempointer(tag);
	if(item != NULL)
	{
		if(item->len > position)
		{
			item->data[position] &= anddata;
		}
	}
	
}

//20140320
void dllemvb_avl_setvalue_or(unsigned char *tag,unsigned short  position,unsigned char ordata)
{
	EMVTAGCVLITEM *item;

	item = dllemvb_avl_gettagitempointer(tag);
	if(item != NULL)
	{
		if(item->len > position)
		{
			item->data[position] |= ordata;
		}
	}
}

//20140320
EMVTAGCVLITEM *dllemvb_avl_gettagitempointerandexiststatus(unsigned char *tag,unsigned char *tagexistflag)
{
    EMVTAGCVLITEM *item;

	*tagexistflag = 0;

	
	item = dllemvb_avl_gettagitempointer(tag);
	if(item != NULL)
	{
		if(item->len)
		{
		    *tagexistflag = 1;
			return item;
		}
	}
    
	
	return NULL;
	
}



//20140320
unsigned char dllemvb_avl_checkiftagexist(unsigned char *tag)
{
	EMVTAGCVLITEM *item;
    
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
    
    
	if(emvtree == NULL)
	{
		return 0;
	}
    
	
	gEmvballocator.EMVBallocator_memset(&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (gEmvballocator.EMVBallocator_strlen((char *)tag)>4) ? 4:(gEmvballocator.EMVBallocator_strlen((char *)tag));
    
    gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
    
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
	if(item == NULL)
	{
		return 0;
	}
    
	return (item->len)?(1):(0);
}


//20140320
void dllemv_avl_settagtype(unsigned int tagtype)
{
	gcurtagtype = tagtype;
}


//20140320
unsigned int dllemv_avl_gettagtype(void)
{
	return gcurtagtype;
}






//20140320
void dllemvb_avl_printtagvalue(unsigned char *title,unsigned char *tag,unsigned short strpos,unsigned short len)
{
    #ifdef EMVB_DEBUG
	EMVTAGCVLITEM *tagitem;
    int i;

    if(title != NULL)
    {
    	emvb_printf("\r\n%s-",title);
    }
	else
	{
		emvb_printf("\r\n");
	}
    
	
    for(i = 0;i < strlen((char *)tag);i++)
    {
		emvb_printf("%02x ",tag[i]);
    }
	emvb_printf(":");
	tagitem = dllemvb_avl_gettagitempointer(tag);
    if(tagitem == NULL)
    {
    	emvb_printf("NULL");
    }
	else
	{
	    emvb_printf("(%d) ",tagitem->len);
		if(tagitem->data != NULL)
		{
			for(i = strpos;i < tagitem->len&&i <(strpos + len);i++)
			{
				emvb_printf("%02x ",tagitem->data[i]);
			}
		}
	}
	emvb_printf("\r\n");

	#endif
	
}

//20140320
void dllemvb_avl_printtagallvalue(unsigned char *title,unsigned char *tag)
{
	#ifdef EMVB_DEBUG
	EMVTAGCVLITEM *tagitem;
    int i;

    if(title != NULL)
    {
    	emvb_printf("\r\n%s-",title);
    }
	else
	{
		emvb_printf("\r\n");
	}
    
	
    for(i = 0;i < strlen((char *)tag);i++)
    {
		emvb_printf("%02x ",tag[i]);
    }
	emvb_printf(":");
	tagitem = dllemvb_avl_gettagitempointer(tag);
    if(tagitem == NULL)
    {
    	emvb_printf("NULL");
    }
	else
	{
	    emvb_printf("(%d) ",tagitem->len);
		if(tagitem->data != NULL)
		{
			for(i = 0;i < tagitem->len;i++)
			{
				emvb_printf("%02x ",tagitem->data[i]);
			}
		}
	}
	emvb_printf("\r\n");

	#endif
}

//20140320
unsigned int gettreetagdata(const void *pa)
{
    
    const EMVTAGCVLITEM *itema = (EMVTAGCVLITEM *)pa;
	unsigned int a = 0;
	int i;


	if(pa == NULL)
    {
    	return 0;
    }
    
    
	for(i = 0;i < 4;i++)
	{
		a = (a<<8) + itema->Tag[i];
	}
    
    

	return a;
}





static void dllemvb_avl_readtreetagdata_all(const struct avl_node *node, int level,unsigned char *tag,int *taglen)
{
	/* You can set the maximum level as high as you like.
	Most of the time, you'll want to debug code using small trees,
	so that a large |level| indicates a ``loop'', which is a bug. */
	
    
	if (level > 16)
	{
		return;
	}
    
	if (node == NULL)
	{
		return;
	}
    
    if((*taglen/100)>30)  
    {
    	return;
    }
	gEmvballocator.EMVBallocator_memcpy(&tag[*taglen],((EMVTAGCVLITEM *)(node->avl_data))->Tag,4);
    *taglen += 4;
    tag[*taglen] = ((EMVTAGCVLITEM *)(node->avl_data))->updatecondition;
	*taglen += 1;
	
    
	
	if ((node->avl_link[0] != NULL) || (node->avl_link[1] != NULL))
	{	  
		if(node->avl_link[0] != NULL)
		{
			dllemvb_avl_readtreetagdata_all (node->avl_link[0], level + 1,tag,taglen);
		}
		if (node->avl_link[1] != NULL)
		{
			dllemvb_avl_readtreetagdata_all (node->avl_link[1], level + 1,tag,taglen);
		}
	}
	
}


//20140320
void dllemvb_avl_readtreetagdatatospecfile(unsigned char *tag,int *taglen)
{
	if(emvtree == NULL)
	{
		return;
	}
    
	dllemvb_avl_readtreetagdata_all(emvtree->avl_root,0,tag,taglen);
}


unsigned char dllemvb_avl_checkiftagempty(unsigned char *tag)
{
	EMVTAGCVLITEM *item;
	
	EMVTAGCVLITEM tempitem;
	unsigned char savetaglen;
	
	
	if(emvtree == NULL)
	{
		return 0;
	}
	
	
	gEmvballocator.EMVBallocator_memset(&tempitem,0,sizeof(EMVTAGCVLITEM));
	savetaglen = (gEmvballocator.EMVBallocator_strlen((char *)tag)>4) ? 4:(gEmvballocator.EMVBallocator_strlen((char *)tag));
	
	gEmvballocator.EMVBallocator_memcpy(tempitem.Tag,tag,savetaglen);
	
	
	item = (EMVTAGCVLITEM *)avl_find (emvtree,(void *)&tempitem);
	if(item == NULL)
	{
		return 0;
	}
	
	return (item->len)?(0):(1);
}

unsigned char dllemvb_avl_checkifRedundantData(unsigned char *tag)
{

	unsigned char temptaglen;    //temptag[4],
	EMVTAGCVLITEM *tagcvlitem = NULL;
	unsigned char ret = 0;
    unsigned char tagdata[4] = {0};


	temptaglen = 1;
    if((tag[0]&0x1f) == 0x1f)
    {
        temptaglen++;
		if(tag[1]&0x80)
		{
			temptaglen++;
		}
    }
	

	memcpy(tagdata, tag, temptaglen);
	tagcvlitem = dllemvb_avl_gettagitempointer(tagdata);
    if(tagcvlitem != NULL)
    {
        if(tagcvlitem->updatecondition&TAGUPDATECONDITION_RA)
        {
            ret = 1;
        }
    }


    return ret;
	
}



